package com.zf.yichat.service.config;

import com.alibaba.fastjson.JSONArray;
import com.zf.yichat.model.Packet;
import com.zf.yichat.utils.YiChatMsgCode;
import com.zf.yichat.utils.common.GeneralUtils;
import com.zf.yichat.utils.common.SysInternPool;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.util.Contracts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 一句话描述功能
 *
 * @author fengsong
 * @date create in 10:59 2019/1/3 2019
 */
@Component
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static String token_pre = "token_";
    private static String token2_pre = "token2_";
    private static String token2_split = "_s_";

    public Long getId(String key) {
        return redisTemplate.boundValueOps(key).increment(1);
    }

    public String setKeyVal(String key) {
        String val = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(key, val);
        return val;
    }

//    public void addToAppIdList(String appId){
//        String appIds=stringRedisTemplate.opsForValue().get("user_appIds");
//        if(appIds!=null){
//            JSONArray jsonArray=JSONArray.parseArray(appIds);
//            jsonArray.add(appId);
//        }else {
//            JSONArray jsonArray=new JSONArray();
//            jsonArray.add(appId);
//        }
//
//
//    }

    public boolean validKey(String key, String val) {
        String store = redisTemplate.opsForValue().get(key).toString();
        return StringUtils.equals(val, store);
    }

    public String getVal(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
    public Boolean delVal(String key) {
        return stringRedisTemplate.delete(key);
    }

    public void setVal(String key, String val) {
        if(val==null){
            return;
        }
        stringRedisTemplate.opsForValue().set(key, val);
    }

    public void setVal(String key, String val, long seconds) {
        stringRedisTemplate.opsForValue().set(key, val, seconds, TimeUnit.SECONDS);
    }


//    public boolean valid(Long userId, String token) {
//        String result = getVal(token_pre + userId);
//        return StringUtils.isNotBlank(result) && result.equals(token);
//    }

    //token 默认设置失效100天
    public void setToken(Long userId, String token) {
        setVal(token_pre + userId, token, 8640000);

    }

    public void setToken2(Long userId, Long time, String token) {
        setVal(token2_pre + userId + token2_split + time, token, 8640000);

    }

    public String getToken(Long userId) {
        return getVal(token_pre + userId);
    }

    public String getToken2(Long userId, Long time) {
        return getVal(token2_pre + userId + token2_split + time);
    }

    public void deleteToken(Long userId) {
        stringRedisTemplate.delete(token_pre + userId);
    }

    public void deleteToken2(Long userId, Long time) {
        stringRedisTemplate.delete(token2_pre + userId + token2_split + time);
    }

    public void setPacketList(Packet packet, List<BigDecimal> list, long hours) {
        packet.setMonyes(list);
        String packetStr = JSONArray.toJSONString(packet);
        //设置抢红包用户存储
        stringRedisTemplate.opsForValue().set("packet_" + packet.getId() + "_user_", "packet", hours, TimeUnit.HOURS);
        list.forEach(v -> {
            redisTemplate.boundListOps("packet_" + packet.getId()).rightPush(v);
        });
        stringRedisTemplate.opsForValue().set("pc_" + packet.getId(), packetStr);
    }


    //营销红包没有过期时间
    public void setPacketSale(String packetId, List<BigDecimal> list) {
        list.forEach(v -> {
            redisTemplate.boundListOps("packet_sale" + packetId).rightPush(v);
        });

        //设置抢红包用户存储
        stringRedisTemplate.opsForValue().set("packet_sale" + packetId + "_user_", "sale");
    }

    //营销红包没有过期时间
    public void setPacketMixuan(String packetId, List<BigDecimal> list) {
        list.forEach(v -> {
            redisTemplate.boundListOps("packet_mixuan" + packetId).rightPush(v);
        });

        //设置抢红包用户存储
        stringRedisTemplate.opsForValue().set("packet_mixuan" + packetId + "_user_", "mixuan");
    }

    //视频红包没有过期时间
    public void setPacketVideo(List<BigDecimal> moneyList, List<Integer> timeList, boolean force) {
        redisTemplate.delete("packet_video_money");
        redisTemplate.delete("packet_video_time");
        moneyList.forEach(v -> redisTemplate.boundListOps("packet_video_money").rightPush(v));
        //        timeList.forEach(v -> redisTemplate.boundListOps("packet_video_time").rightPush(v));
        if (force) {
            //删除所有用户key，强制重新复制红包列表
            Set<String> keys = redisTemplate.keys("packet_video_user_" + "*");
            redisTemplate.delete(keys);
        }
    }

    /**
     * 重置指定用户的vip红包
     *
     * @param moneyList
     * @param userId
     */
    public void resetPacketVip(List<BigDecimal> moneyList, Long userId) {
        String key = "packet_vip_user_money_" + userId;
        redisTemplate.delete(key);
        moneyList.forEach(v -> redisTemplate.boundListOps(key).rightPush(v));
    }

    /**
     * 删除所有用户红包，强制重新计算红包金额
     */
    public void deleteAllPacketVip() {
        Set<String> keys = redisTemplate.keys("packet_vip_user_money_" + "*");
        redisTemplate.delete(keys);
    }

    /**
     * 设置用户的视频红包
     *
     * @param userId
     */
    public void setUserPacketVideo(String userId, int count) {
        List<BigDecimal> moneyList = redisTemplate.opsForList().range("packet_video_money", 0, -1);
        //        List<Integer> timeList = redisTemplate.opsForList().range("packet_video_time", 0, -1);
        //        if (Objects.nonNull(timeList) && Objects.nonNull(moneyList)) {
        if (Objects.nonNull(moneyList)) {
            redisTemplate.delete("packet_video_user_money_" + userId);
            redisTemplate.delete("packet_video_user_time_" + userId);
            //删除已经领过的次数
            for (int i = 0; i < moneyList.size(); i++) {
                if (i >= count) {
                    redisTemplate.boundListOps("packet_video_user_money_" + userId).rightPush(moneyList.get(i));
                    //                    redisTemplate.boundListOps("packet_video_user_time_" + userId).rightPush(timeList.get(i));
                }
            }
        }
    }

    /**
     * 设置用户的vip红包
     *
     * @param userId
     */
    public void setUserPacketVip(String userId, int count) {
        List<BigDecimal> moneyList = redisTemplate.opsForList().range("packet_vip_money", 0, -1);
        if (Objects.nonNull(moneyList)) {
            redisTemplate.delete("packet_vip_user_money_" + userId);
            //删除已经领过的次数
            for (int i = 0; i < moneyList.size(); i++) {
                if (i >= count) {
                    redisTemplate.boundListOps("packet_vip_user_money_" + userId).rightPush(moneyList.get(i));
                }
            }
        }
    }

    /**
     * @param packetId
     * @param userId
     * @param type
     * @return
     */
    public BigDecimal getMixuanPacket(String packetId, Long userId, int type) {

        String key = "packet_mixuan" + packetId + "_user_";


        String res = stringRedisTemplate.opsForValue().get(key);
        if (Objects.isNull(res)) {
            return BigDecimal.ZERO;
        }

        //标识已抢过
        if (res.contains(String.valueOf(userId))) {
            return BigDecimal.ZERO;
        }

        BigDecimal bigDecimal = null;
        BoundListOperations operations = redisTemplate.boundListOps("packet_mixuan" + packetId);

        int size = (int) getMixuanPacketSize(packetId);
        if (size == 0) {
            //已无红包 删除缓存数据
            deletePacketMixuanKey(packetId);
            return bigDecimal;
        }
        bigDecimal = (BigDecimal) operations.rightPop();

        if (Objects.nonNull(bigDecimal)) {
            stringRedisTemplate.opsForValue().set(key, (StringUtils.isBlank(res) ? "" : res) + "," + userId);
        } else {
            //已无红包 删除缓存数据
            deletePacketMixuanKey(packetId);
        }

        return bigDecimal;
    }

    /**
     * 根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
     *
     * @param packetId
     * @param userId
     * @param type
     * @return
     */
    public BigDecimal getSalePacket(String packetId, Long userId, int type) {

        String key = "packet_sale" + packetId + "_user_";


        String res = stringRedisTemplate.opsForValue().get(key);
        if (Objects.isNull(res)) {
            return BigDecimal.ZERO;
        }

        //标识已抢过
        if (res.contains(String.valueOf(userId))) {
            return BigDecimal.ZERO;
        }

        //根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
        BigDecimal bigDecimal = null;

        int size = (int) getSalePacketSize(packetId);
        if (size == 0) {
            //已无红包 删除缓存数据
            deletePacketSaleKey(packetId);
            return bigDecimal;
        }
        BoundListOperations operations = redisTemplate.boundListOps("packet_sale" + packetId);
        int index;
        switch (type) {
            case 0:
                index = GeneralUtils.randomInt(0, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 1:
                index = GeneralUtils.randomInt(0, size / 2);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 2:
                index = GeneralUtils.randomInt(size / 2, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 3:
                bigDecimal = (BigDecimal) operations.rightPop();
                break;
            case 4:
                bigDecimal = (BigDecimal) operations.leftPop();
                break;
        }

        if (Objects.nonNull(bigDecimal)) {
            stringRedisTemplate.opsForValue().set(key, (StringUtils.isBlank(res) ? "" : res) + "," + userId);
        } else {
            //已无红包 删除缓存数据
            deletePacketSaleKey(packetId);
        }

        return bigDecimal;
    }

    /**
     * 根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
     *
     * @param userId
     * @param type
     * @return 无红包则返回null，否则返回红包值
     */
    public BigDecimal getPacketVideoMoney(String userId, int type) {

        String key = "packet_video_user_money_" + userId;
        BigDecimal bigDecimal = BigDecimal.ZERO;

        BoundListOperations operations = redisTemplate.boundListOps(key);
        int size = Math.toIntExact(Optional.ofNullable(operations.size()).orElse(0L));
        //红包申请还没领时被强制重置会出现size=0的情况
        if (size == 0) {
            return bigDecimal;
        }
        //根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
        int index;
        switch (type) {
            case 0:
                index = GeneralUtils.randomInt(0, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 1:
                index = GeneralUtils.randomInt(0, size / 2);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 2:
                index = GeneralUtils.randomInt(size / 2, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 3:
                bigDecimal = (BigDecimal) operations.rightPop();
                break;
            case 4:
                bigDecimal = (BigDecimal) operations.leftPop();
                break;
        }

        return bigDecimal;
    }

    /**
     * 根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
     *
     * @param userId
     * @param type
     * @return 无红包则返回null，否则返回红包值
     */
    public BigDecimal getPacketVipMoney(String userId, int type) {

        String key = "packet_vip_user_money_" + userId;
        BigDecimal bigDecimal = BigDecimal.ZERO;

        BoundListOperations operations = redisTemplate.boundListOps(key);
        int size = Math.toIntExact(Optional.ofNullable(operations.size()).orElse(0L));
        //红包申请还没领时被强制重置会出现size=0的情况
        if (size == 0) {
            return bigDecimal;
        }
        //根据type获取红包金额  随机0 低于平均1  高于平均2  最大3 最小4
        int index;
        switch (type) {
            case 0:
                index = GeneralUtils.randomInt(0, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 1:
                index = GeneralUtils.randomInt(0, size / 2);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 2:
                index = GeneralUtils.randomInt(size / 2, size - 1);
                bigDecimal = (BigDecimal) operations.index(index);
                operations.remove(1, bigDecimal);
                break;
            case 3:
                bigDecimal = (BigDecimal) operations.rightPop();
                break;
            case 4:
                bigDecimal = (BigDecimal) operations.leftPop();
                break;
        }

        return bigDecimal;
    }

    /**
     * 根据type获取领红包时间  随机0 低于平均1  高于平均2  最大3 最小4
     *
     * @param userId
     * @param type
     * @return 无红包则返回null，否则返回时间
     */
    public Integer getPacketVideoTime(String userId, int type) {

        String key = "packet_video_user_time_" + userId;
        Integer time = null;

        BoundListOperations operations = redisTemplate.boundListOps(key);
        int size = Math.toIntExact(Optional.ofNullable(operations.size()).orElse(0L));
        //强制重置、领完、或者第一次领会出现size=0
        if (size == 0) {
            return time;
        }

        //根据type获取  随机0 低于平均1  高于平均2  最大3 最小4
        int index;
        switch (type) {
            case 0:
                index = GeneralUtils.randomInt(0, size - 1);
                time = (Integer) operations.index(index);
                operations.remove(1, time);
                break;
            case 1:
                index = GeneralUtils.randomInt(0, size / 2);
                time = (Integer) operations.index(index);
                operations.remove(1, time);
                break;
            case 2:
                index = GeneralUtils.randomInt(size / 2, size - 1);
                time = (Integer) operations.index(index);
                operations.remove(1, time);
                break;
            case 3:
                time = (Integer) operations.rightPop();
                break;
            case 4:
                time = (Integer) operations.leftPop();
                break;
        }

        return time;
    }

    //获取红包剩余个数
    public long getSalePacketSize(String packetId) {
        return Optional.ofNullable(redisTemplate.boundListOps("packet_sale" + packetId).size()).orElse(0L);
    }

    //获取红包剩余个数
    public long getMixuanPacketSize(String packetId) {
        return Optional.ofNullable(redisTemplate.boundListOps("packet_mixuan" + packetId).size()).orElse(0L);
    }

    //获取红包剩余个数
    public long getPacketSize(Long packetId) {
        return Optional.ofNullable(redisTemplate.boundListOps("packet_" + packetId).size()).orElse(0L);
    }

    public void deleteKey(Long id) {
        stringRedisTemplate.delete("packet_" + id);
        stringRedisTemplate.delete("pc_" + id);
        stringRedisTemplate.delete("packet_" + id + "_user_");
    }

    public void deleteKey(String key) {
        stringRedisTemplate.delete(key);
    }

    public void deletePacketSaleKey(String id) {
        stringRedisTemplate.delete("packet_sale" + id);
        stringRedisTemplate.delete("packet_sale" + id + "_user_");
    }

    public void deletePacketMixuanKey(String id) {
        stringRedisTemplate.delete("packet_mixuan" + id);
        stringRedisTemplate.delete("packet_mixuan" + id + "_user_");
    }

    public BigDecimal getReceive(Long packetId, Long userId) {
        synchronized (SysInternPool.INSTANCE.internUid(packetId)) {
            String key = "packet_" + packetId + "_user_";

            String res = stringRedisTemplate.opsForValue().get(key);
            //标识下设置失效时间  用于清理数据 不必担心  超过时效时间 接口已过滤
            Contracts.assertNotNull(res, YiChatMsgCode.PACKET_RECEIVE_OVER_TIME.msg());

            //标识已抢过
            if (res.contains(String.valueOf(userId))) {
                return BigDecimal.ZERO;
            }

            Long expire = stringRedisTemplate.getExpire(key);
            stringRedisTemplate.opsForValue().set(key, (StringUtils.isBlank(res) ? "" : res) + "," + userId, Objects.isNull(expire) ? 0 : expire, TimeUnit.SECONDS);

            BigDecimal bigDecimal = (BigDecimal) redisTemplate.boundListOps("packet_" + packetId).leftPop();

            return bigDecimal;
        }
    }
}
